package middleware

import (
	"context"
	"regexp"
	"time"

	"system-admin/config/redis"
	"system-admin/internal/app/grpc/client"
	"system-admin/internal/app/grpc/protoc/devicec"
	"system-admin/internal/define"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/logx"
	"192.168.1.75/go-pkg/response"
	"github.com/gin-gonic/gin"
)

// NonAuthAPIs 免认证接口
var NonAuthAPIs = []string{
	"/health",                // 健康检查
	"^(/robot)",              // 安卓终端调用
	"^(/advertise)",          // 安卓终端调用
	"/admin/pay",             // 支付回调，验证码
	"/admin/activity",        // 活动页
	"/public",                // 公共
	"/system-admin/login",    // 登录
	"/system-admin/captcha",  // 获取验证码
	"/system-admin/login-v2", // 登录
	"/system-admin/logout",   // 退出
	"^(/open-api)",           // 开放接口
	"/be-file/",              // 后端静态文件
	"^(/mini-app/web)",       // 小程序
	"^(/mini-app/advertisement)",       // 小程序广告
	"/nonauth",               // 无需验证
}

// Auth 鉴权
// 认证及接口鉴权
func Auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		pattern := regexp.MustCompile(`\/+`)
		urlPath := string(pattern.ReplaceAll([]byte(c.Request.URL.Path), []byte("/")))
		c.Request.URL.Path = urlPath
		// 跳过白名单接口
		for _, nonAuthApi := range NonAuthAPIs {
			reg := regexp.MustCompile(nonAuthApi)
			if reg.MatchString(c.Request.URL.Path) {
				c.Next()
				return
			}
		}
		// 授权验证
		{
			logx.Info(context.Background(), "c.Request.URL.Path: "+c.Request.URL.Path)
			// 登录鉴权
			if !LoginAuth(c) {
				// 开放接口鉴权
				if reg := regexp.MustCompile("/open-api"); reg.MatchString(c.Request.URL.Path) {
					if OpenAPIAuth(c) {
						c.Next()
						return
					} else {
						response.JSON(c, nil, errorx.New("请重新登录", 100001))
						c.Abort()
						return
					}
					// 设备端鉴权
				} else if reg := regexp.MustCompile("^(/device-admin/robot)"); reg.MatchString(c.Request.URL.Path) {
					if RobotAPIAuth(c) {
						c.Next()
						return
					} else {
						response.JSON(c, nil, errorx.New("无效的认证", 100001))
						c.Abort()
						return
					}
				} else {
					response.JSON(c, nil, errorx.New("请重新登录", 40306))
					c.Abort()
					return
				}
			}
		}
		c.Next()
	}
}

// LoginAuth 登录鉴权
func LoginAuth(c *gin.Context) bool {
	authorizationToken := c.GetHeader("Authorization")
	if authorizationToken == "" {
		if authorizationToken = c.Query("Authorization"); authorizationToken == "" {
			return false
		}
	}
	// redis超时控制
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()
	exists, _ := redis.NewDB().HExists(ctx, define.RedisUserLoginToken+authorizationToken, "user_id").Result()
	if !exists {
		return false
	}
	// token延长有效期
	redis.NewDB().Expire(ctx, define.RedisUserLoginToken+authorizationToken, time.Hour*2)
	return true
}

// 开放接口
func OpenAPIAuth(c *gin.Context) bool {
	apiToken := c.GetHeader("APIToken")
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()
	exists, _ := redis.NewDB().HExists(ctx, define.RedisMerchantAPITokenList, apiToken).Result()
	return exists
}

// 设备访问认证
func RobotAPIAuth(c *gin.Context) bool {
	// 以下代码可实现，body的内容可以重复读取，否则steam流被破坏
	// body, _ := c.GetRawData()
	// c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
	// defer func() {
	// 	c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
	// }()
	authorizationToken := c.GetHeader("Authorization")
	if authorizationToken == "" {
		if authorizationToken = c.Query("Authorization"); authorizationToken == "" {
			return false
		}
	}
	cli, err := client.GetDeviceAdminClient()
	if err != nil {
		logx.Error(context.Background(), "RobotAPIAuth get device detail failed", logx.Err(err))
		return false
	}
	rsp, err := cli.DeviceDetail(c.Request.Context(), &devicec.DeviceDetailReq{
		IdentificationCode: authorizationToken,
	})
	if err != nil {
		return false
	}
	if rsp != nil && rsp.Device != nil {
		return authorizationToken == rsp.Device.IdentificationCode
	} else {
		logx.Error(context.Background(), "RobotAPIAuth faild", logx.String("authorization", authorizationToken))
		return false
	}
}
